package org.cogaen.demo.state;

import java.util.ArrayList;
import java.util.Iterator;

import org.cogaen.box2d.PhysicsService;
import org.cogaen.core.Core;
import org.cogaen.demo.entity.ShipEntity;
import org.cogaen.demo.view.GameDemoView;
import org.cogaen.entity.EntityManager;
import org.cogaen.event.EventType;
import org.cogaen.resource.ResourceManager;
import org.cogaen.state.GameState;
import org.jbox2d.collision.PolygonDef;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.Body;
import org.jbox2d.dynamics.BodyDef;
import org.jbox2d.dynamics.World;

public class GameDemoState implements GameState {

	/** Unique name of this state. */
	public static final String NAME = "Game Demo";
	
	/** Width of game world in meters. */
	public static final double WORLD_WIDTH = 48.0;

	/** Height of game world in meters. */
	public static final double WORLD_HEIGHT = 36.0;
	
	/** Name of entity for player one. */
	public static final String PLAYER_ENTITY = "Player1";

	public static final double EARTH_GRAVITY = 9.81;
	public static final double MOON_GRAVITY = 1.62;
	public static final double GRAVITY = EARTH_GRAVITY;
	
	public static final EventType END_OF_GAME = new EventType("EndOfGame");
	private static final String RES_GROUP = NAME;
	
	private Core core;
	private GameDemoView view;
	private ArrayList<Body> staticObjects = new ArrayList<Body>();
	
	public GameDemoState(Core core) {
		this.core = core;
		this.view = new GameDemoView(core);		
		this.view.registerResources(RES_GROUP);
	}
	
	@Override
	public String getName() {
		return NAME;
	}

	@Override
	public void onEnter() {
		ResourceManager.getInstance(this.core).loadGroup(RES_GROUP);
		createLevel();
		this.view.engage();
	}

	@Override
	public void onExit() {
		this.view.disengage();
		destroyLevel();
		ResourceManager.getInstance(this.core).unloadGroup(RES_GROUP);
	}
	
	private void createLevel() {
		PhysicsService.getInstance( this.core ).setGravity(0, -GRAVITY);
		
		float width2 = (float) (WORLD_WIDTH * 0.5);
		float height2 = (float) (WORLD_HEIGHT * 0.5);
		World world = PhysicsService.getInstance( this.core ).getWorld();
		
		// create floor
		BodyDef def = new BodyDef();
		def.position.x = 0.0f;
		def.position.y = -height2 - 0.5f;
		Body body = world.createBody(def);
		
		PolygonDef polyDef = new PolygonDef();
		polyDef.setAsBox(width2, 0.5f);
		body.createShape(polyDef);		
		staticObjects.add(body);
		
		// create ceiling
		def.position.x = 0.0f;
		def.position.y = height2 + 0.5f;
		body = world.createBody(def);;
		polyDef.setAsBox(width2, 0.5f);
		body.createShape(polyDef);		
		staticObjects.add(body);
		
		// create left wall
		def.position.x = -width2 - 0.5f;
		def.position.y = 0.0f;
		body = world.createBody(def);;
		polyDef.setAsBox(0.5f, height2);
		body.createShape(polyDef);		
		staticObjects.add(body);

		// create right wall
		def.position.x = width2 + 0.5f;
		def.position.y = 0.0f;
		body = world.createBody(def);;
		polyDef.setAsBox(0.5f, height2);
		body.createShape(polyDef);				
		staticObjects.add(body);

		// create obstacle #1
		def.position.x = -19.0f;
		def.position.y = -7.0f;
		body = world.createBody(def);
		polyDef.clearVertices();
		polyDef.addVertex( new Vec2(7.0f, 0.0f) );
		polyDef.addVertex( new Vec2(6.0f, 1.0f) );
		polyDef.addVertex( new Vec2(-6.0f, 1.0f) );
		polyDef.addVertex( new Vec2(-7.0f, 0.0f) );
		polyDef.addVertex( new Vec2(-6.0f, -1.0f) );
		polyDef.addVertex( new Vec2(6.0f, -1.0f) );
		body.createShape(polyDef);				
		staticObjects.add(body);
		
		// create obstacle #2
		def.position.x = 11.0f;
		def.position.y = -5.0f;
		body = world.createBody(def);
		polyDef.clearVertices();
		polyDef.addVertex( new Vec2(13.0f, 17.0f) );
		polyDef.addVertex( new Vec2(11.0f, 17.0f) );
		polyDef.addVertex( new Vec2(5.0f, 13.0f) );
		polyDef.addVertex( new Vec2(13.0f, 13.0f) );
		body.createShape(polyDef);				
		polyDef.clearVertices();
		polyDef.addVertex( new Vec2(13.0f, 13.0f) );
		polyDef.addVertex( new Vec2(-8.0f, 13.0f) );
		polyDef.addVertex( new Vec2(-9.0f, 12.0f) );
		polyDef.addVertex( new Vec2(-9.0f, 4.0f) );
		polyDef.addVertex( new Vec2(13.0f, 4.0f) );
		body.createShape(polyDef);				
		polyDef.clearVertices();
		polyDef.addVertex( new Vec2(-9.0f, 4.0f) );
		polyDef.addVertex( new Vec2(-16.0f, 2.0f) );
		polyDef.addVertex( new Vec2(-16.0f, -13.0f) );
		polyDef.addVertex( new Vec2(-9.0f, -13.0f) );
		body.createShape(polyDef);				
		staticObjects.add(body);
		
		// create player entity
		EntityManager.getInstance(this.core).addEntity( new ShipEntity(this.core, PLAYER_ENTITY, -10, 10, 0.0) );		
	}
	
	private void destroyLevel() {
		World world = PhysicsService.getInstance( this.core ).getWorld();
		
		for (Iterator<Body> it = this.staticObjects.iterator(); it.hasNext(); ) {
			world.destroyBody( it.next() );
		}
		this.staticObjects.clear();
		
		EntityManager.getInstance( this.core ).removeAllEntities();
	}

}
